var utilsDefaults = require('./utilsDefaults')
var isObject = require('./isObject')
// 收集依赖
var weakMap = new WeakMap()
/**
 * @description 创建收集依赖
 * @param {*} target
 * @param {*} key
 */
function track(target, key) {
    const active = globalThis.__utils_activeEffect;

    if (!active) return;

    let depMap = weakMap.get(target)
    if (!depMap) {
        depMap = new Map()
        weakMap.set(target, depMap)
    }

    let depSet = depMap.get(target)
    if (!depSet) {
        depSet = new Set()
        depMap.set(key, depSet)
    }

    depSet.add(active)
}

/**
 * @description 触发依赖
 * @param {*} target
 * @param {*} key
 */
function trigger(target, key) {
    const mapTarget = weakMap.get(target)
    if (mapTarget) {
        const setTarget = mapTarget.get(key)
        setTarget.forEach(active => active());
    }
}

const baseReactiveHandler = {
    get(target, key, receiver) {
        // 判断是否是reactiveFlag属性，如果是则返回true
        if (key === utilsDefaults.reactiveFlag) return true;
        // Reflect.get() 方法与从 对象 (target[propertyKey]) 中读取属性类似，但它是通过一个函数执行来操作的。
        const value = Reflect.get(target, key, receiver);
        // 创建依赖收集
        track(target, key)

        return isObject(value)? reactive(value) : value;
    },
    set(target, key, value, receiver) {
        // Reflect.set() 方法与向对象 (target[propertyKey]) 写入属性类似，但它是通过一个函数执行来操作的。
        const result = Reflect.set(target, key, value, receiver);
        // 触发依赖收集
        if (result) trigger(target, key)
        return result;
    },
    deleteProperty(target, key){
        return Reflect.deleteProperty(target, key)
    }
}

function createReactiveProxy(target) {
    // 判断是否传入了有效的对象，如果传入的对象不是对象或者为null，则直接返回该对象
    if (!isObject(target)) return target;

    // 判断是否已经创建过代理对象，如果已经创建过，则直接返回该对象
    if (target[utilsDefaults.reactiveFlag]) {
        return target;
    }

    // 创建代理对象，并设置代理对象的属性和行为
    const proxy = new Proxy(target, baseReactiveHandler);
    // 返回代理对象
    return proxy
}

/**
 * @description: 创建响应式对象
 * @param {target} 目标对象
 * @return: 
 */
function reactive(target) {
    return createReactiveProxy(target);
}

module.exports = reactive